package org.zn.note.designpattern;

import java.util.ArrayList;
import java.util.List;

/**
 * 建造者模式（Builder Pattern）
 * 针对复杂对象的复杂创建过程，拆分成一步一步的，将“变”与“不变”的创建步骤分离，更好的适应变化。
 * <p>
 * 一家汉堡店
 * {@link Item} 所有吃的总接口，方法有：名字{@link Item#name()}、打包方式{@link Item#packing()}、价格{@link Item#price()}
 * 吃的分两大类：汉堡{@link Burger}、冷饮{@link ColdDrink}，实现了“打包方式”，但是没实现“名字”和“价格”
 * 打包：{@link Packing} --> {@link Wrapper} 用纸打包(汉堡)、{@link Bottle} 用杯打包(冷饮)
 * 具体吃的：{@link ChickenBurger}、{@link VegBurger}、{@link Coke}、{@link Pepsi}
 * <p>
 * 一顿饭，是N个吃的组合，{@link Meal} 是这样的数据结构
 * 具体这顿饭吃什么，{@link MealBuilder} 进行创建 Meal
 */
public class Pattern04_Builder {

    public static void main(String[] args) {
        MealBuilder mealBuilder = new MealBuilder();

        Meal vegMeal = mealBuilder.prepareVegMeal();
        System.out.println("Veg Meal");
        vegMeal.showItems();
        System.out.println("Total Cost: " + vegMeal.getCost());

        Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
        System.out.println("\n\nNon-Veg Meal");
        nonVegMeal.showItems();
        System.out.println("Total Cost: " + nonVegMeal.getCost());
    }

    private interface Packing {
        String pack();
    }

    public interface Item {
        String name();

        Packing packing();

        float price();
    }

    //
    private static class Wrapper implements Packing {
        @Override
        public String pack() {
            return "Wrapper";
        }
    }

    private static class Bottle implements Packing {
        @Override
        public String pack() {
            return "Bottle";
        }
    }

    private static abstract class Burger implements Item {
        @Override
        public Packing packing() {
            return new Wrapper();
        }

        @Override
        public abstract float price();
    }

    private static abstract class ColdDrink implements Item {
        @Override
        public Packing packing() {
            return new Bottle();
        }

        @Override
        public abstract float price();
    }

    private static class VegBurger extends Burger {
        @Override
        public float price() {
            return 25.0f;
        }

        @Override
        public String name() {
            return "Veg Burger";
        }
    }

    private static class ChickenBurger extends Burger {
        @Override
        public float price() {
            return 50.5f;
        }

        @Override
        public String name() {
            return "Chicken Burger";
        }
    }

    private static class Coke extends ColdDrink {
        @Override
        public float price() {
            return 30.0f;
        }

        @Override
        public String name() {
            return "Coke";
        }
    }

    private static class Pepsi extends ColdDrink {
        @Override
        public float price() {
            return 35.0f;
        }

        @Override
        public String name() {
            return "Pepsi";
        }
    }

    private static class Meal {
        private List<Item> items = new ArrayList<Item>();

        public void addItem(Item item) {
            items.add(item);
        }

        public float getCost() {
            float cost = 0.0f;
            for (Item item : items) {
                cost += item.price();
            }
            return cost;
        }

        public void showItems() {
            for (Item item : items) {
                System.out.print("Item : " + item.name());
                System.out.print(", Packing : " + item.packing().pack());
                System.out.println(", Price : " + item.price());
            }
        }
    }

    private static class MealBuilder {

        public Meal prepareVegMeal() {
            Meal meal = new Meal();
            meal.addItem(new VegBurger());
            meal.addItem(new Coke());
            return meal;
        }

        public Meal prepareNonVegMeal() {
            Meal meal = new Meal();
            meal.addItem(new ChickenBurger());
            meal.addItem(new Pepsi());
            return meal;
        }
    }
}
